﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FlexiCache;
using System.Collections.Specialized;

namespace CLOComponentlibCSFixture.FlexiCache
{
    [TestClass()]
    public class MongoDBCacheStorageAdapterPerformanceTestsFixture
    {
        MongoDBCacheStorageAdapter _adapter;

        [TestInitialize]
        public void BeforeTest()
        {
            _adapter = new MongoDBCacheStorageAdapter();
            _adapter.IsEnabled = true;
            _adapter.CacheDatabaseName = "MongoDBCache";
            _adapter.IsAcknowledgedWrite = true;
            _adapter.MaxDataSizeLength = 0;
            _adapter.TracePrefix = "MongoDBCacheStorageAdapter";
            _adapter.UseCompression = true;
            _adapter.DBConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["objectStore"].ConnectionString;
        }

        [TestCleanup]
        public void TearDown()
        {
            _adapter.Dispose();
        }

        [TestMethod]
        [Ignore()]
        public void Test001_SpeedtestRandom()
        {
            System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
            timer.Start();
            System.Diagnostics.Stopwatch timer2 = new System.Diagnostics.Stopwatch();
            string key = "";
            List<string> keysCollection = new List<string>();
            byte[] data = null;
            Random rnd = new Random(DateTime.Today.Millisecond);
            Random rndKeyGetter = new Random(DateTime.Today.Millisecond);
            Random rndOp = new Random(DateTime.Today.Millisecond);
            int iterationCount = 30000;
            System.Security.Cryptography.RandomNumberGenerator gen = System.Security.Cryptography.RandomNumberGenerator.Create();
            //save 1 item
            key = Guid.NewGuid().ToString();
            keysCollection.Add(key);
            data = new byte[rnd.Next(5000, 1000000)];//~5Kb- ~1Mb
            gen.GetBytes(data);
            _adapter.Add(key, data, DateTime.UtcNow.AddSeconds(10000), "");
            System.Text.StringBuilder sbr = new StringBuilder("DB,Op,Length,Duration\n");
            //run test
            for (int ii = 0; ii < iterationCount; ii++)
            {
                switch (rndOp.Next(4))
                {
                    case 0://add
                        key = Guid.NewGuid().ToString();
                        keysCollection.Add(key);
                        data = new byte[rnd.Next(5000, 1000000)];//~5Kb- ~1Mb
                        gen.GetBytes(data);
                        timer2.Restart();
                        _adapter.Add(key, data, DateTime.UtcNow.AddSeconds(10000), "");
                        sbr.AppendFormat("M,1,{0},{1}\n", data.Length.ToString(), timer2.Elapsed.TotalMilliseconds.ToString("F2"));
                        break;
                    case 1://get
                        key = keysCollection[rndKeyGetter.Next(0, keysCollection.Count)];
                        timer2.Restart();
                        data = (byte[])_adapter.Get(key);
                        sbr.AppendFormat("M,2,{0},{1}\n", data.Length.ToString(), timer2.Elapsed.TotalMilliseconds.ToString("F2"));
                        break;
                    case 2://remove
                        if (keysCollection.Count > 50)
                        {
                            key = keysCollection[rndKeyGetter.Next(0, keysCollection.Count)];
                            keysCollection.Remove(key);
                            timer2.Restart();
                            _adapter.Remove(key);
                            sbr.AppendFormat("M,3,{0},{1}\n", data.Length.ToString(), timer2.Elapsed.TotalMilliseconds.ToString("F2"));
                        }
                        break;
                    case 3://set (update)
                    case 4:
                        key = keysCollection[rndKeyGetter.Next(0, keysCollection.Count)];
                        data = new byte[rnd.Next(5000, 1000000)];//~5Kb- ~1Mb
                        gen.GetBytes(data);
                        timer2.Restart();
                        _adapter.TrySet(key, data, DateTime.UtcNow.AddSeconds(10000), "");
                        sbr.AppendFormat("M,4,{0},{1}\n", data.Length.ToString(), timer2.Elapsed.TotalMilliseconds.ToString("F2"));
                        break;
                }
            }
            timer.Stop();
            _adapter.RemoveAll();
            System.Diagnostics.Trace.WriteLine(string.Format("Speedtest for {0} completed in {1} ms. Avg: {2} ms.", iterationCount.ToString(), timer.ElapsedMilliseconds.ToString(), (Convert.ToDecimal(timer.ElapsedMilliseconds) / Convert.ToDecimal(iterationCount)).ToString("F2")));
            System.IO.File.WriteAllText(@"C:\outputTestRandom_SpeedtestMongoDB.csv", sbr.ToString());
        }

        [TestMethod]
        public void Test002_ShouldNotSaveTooBigObject()
        {
            string key = "98762";
            _adapter.MaxDataSizeLength = 0;
            _adapter.UseCompression = false;
            System.Security.Cryptography.RandomNumberGenerator gen = System.Security.Cryptography.RandomNumberGenerator.Create();
            byte[] data = new byte[10000000];//<16Mb
            _adapter.Add(key, data, DateTime.UtcNow.AddSeconds(100), "");
            object tmp = _adapter.Get(key);
            Assert.IsNotNull(tmp);
            Assert.AreEqual(data.Length, ((byte[])tmp).Length);
            _adapter.Remove(key);

            data = new byte[20000000];//>16Mb
            bool isOk = false;
            try
            {
                _adapter.Add(key, data, DateTime.UtcNow.AddSeconds(100), "");
            }
            catch (Exception ex)
            {
                if (!ex.Message.Contains("Size 20000162 is larger than MaxDocumentSize 16777216."))
                    throw;
                isOk = true;
            }
            tmp = _adapter.Get(key);

            Assert.IsTrue(isOk || tmp == null);

            _adapter.Remove(key);
        }

        [TestMethod]
        public void Test022_ShouldRemoveObjectByMetatags2FromCache()
        {
            string key = "08977-2";

            _adapter.RemoveAll();
            _adapter.Add(key, "Document to be deleted", DateTime.UtcNow.AddSeconds(100), "", new string[] { "test=yes", "userid=123" });
            _adapter.Remove(new string[] { "userid=123" });

            var obj = _adapter.Get(key);

            Assert.IsNull(obj);
        }

        [TestMethod]
        public void Test023_ShouldRemoveObjectByMetatags3FromCache()
        {
            string key = "08977-3";

            _adapter.RemoveAll();
            _adapter.Add(key, "Document to be deleted", DateTime.UtcNow.AddSeconds(100), "", new string[] { "test=yes", "userid=123" });
            _adapter.Remove(new string[] { "test=yes" });

            var obj = _adapter.Get(key);

            Assert.IsNull(obj);
        }

        [TestMethod]
        public void Test024_ShouldNotRemoveObjectByMetatags4FromCache()
        {
            string key = "08977-4";

            _adapter.RemoveAll();
            _adapter.Add(key, "Document to be deleted", DateTime.UtcNow.AddSeconds(100), "", new string[] { "test=yes", "userid=123" });
            _adapter.Remove(new string[] { "test=no" });

            var obj = _adapter.Get(key);

            Assert.IsNotNull(obj);
        }

        [TestMethod]
        public void Test025_ShouldNotRemoveObjectByMetatags5FromCache()
        {
            string key = "08977-5";

            _adapter.RemoveAll();
            _adapter.Add(key, "Document to be deleted", DateTime.UtcNow.AddSeconds(100), "", new string[] { "test=_yes", "user_id=1_23" });
            _adapter.Remove(new string[] { "user_id=1_23" });

            var obj = _adapter.Get(key);

            Assert.IsNull(obj);
        }

        [TestMethod]
        public void Test026_ShouldContainCachedObject()
        {
            string key = "08977-26";

            _adapter.RemoveAll();
            _adapter.Add(key, "Document to test", DateTime.UtcNow.AddSeconds(100), "", new string[] { "test=yes", "userid=123" });
            bool contains = _adapter.Contains(key);

            Assert.IsTrue(contains);
        }

        [TestMethod]
        public void Test027_ShouldNotContainCachedObject()
        {
            string key = "08977-27";

            _adapter.RemoveAll();
            _adapter.Add(key, "Document to test", DateTime.UtcNow.AddSeconds(100), "", new string[] { "test=yes", "userid=123" });
            _adapter.Remove(new string[] { "userid=123" });
            bool contains = _adapter.Contains(key);

            Assert.IsFalse(contains);
        }
    }
}
